package algorithm_demo.leetcode;

import java.util.Deque;
import java.util.LinkedList;

/**
 * 99. 恢复二叉搜索树
 * <a href="https://leetcode.cn/problems/recover-binary-search-tree/">https://leetcode.cn/problems/recover-binary-search-tree/</a>
 *
 * 二叉搜索树的中序遍历是递增的
 *
 * 有效 二叉搜索树定义如下：
 *
 * 节点的左子树只包含 小于 当前节点的数。
 * 节点的右子树只包含 大于 当前节点的数。
 * 所有左子树和右子树自身必须也是二叉搜索树。
 *
 * @author Api
 * @date 2023/4/30 15:37
 */
public class Problem_099_RecoverBinarySearchTree {


    public static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode() {
        }

        TreeNode(int val) {
            this.val = val;
        }

        TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }

    public void recoverTree1(TreeNode root) {
        if (root == null){
            return;
        }
        Deque<TreeNode> stack = new LinkedList<>();
        TreeNode firstNode = null;
        TreeNode secondaryNode = null;
        TreeNode pre = new TreeNode(Integer.MIN_VALUE);
        TreeNode p = root;
        while(p != null || !stack.isEmpty()){
            while(p!= null){
                stack.push(p);
                p = p.left;
            }
            p = stack.pop();
            if (firstNode == null && pre.val > p.val){
                firstNode = pre;
            }
            if (firstNode != null && pre.val > p.val){
                secondaryNode = p;
            }
            pre = p;
            p = p.right;
        }
        if (firstNode != null){
            int tmp = firstNode.val;
            firstNode.val = secondaryNode.val;
            secondaryNode.val = tmp;
        }
    }
    /*该题目一定需要找到对应的两个交换的节点*/
    TreeNode firstNode = null;
    TreeNode secondNode = null;
    TreeNode preNode = new TreeNode(Integer.MIN_VALUE);

    public void recoverTree2(TreeNode root) {
        in_order(root);
        int tmp = firstNode.val;
        firstNode.val = secondNode.val;
        secondNode.val = tmp;
    }
    /*中序遍历*/
    private void in_order(TreeNode root) {
        if (root == null) {
            return;
        }
        in_order(root.left);
        //这里主要利用二叉搜索树中序遍历时，是递增序列
        if (firstNode == null && preNode.val > root.val) {
            firstNode = preNode;
        }
        if (firstNode != null && preNode.val > root.val) {
            secondNode = root;
        }
        preNode = root;
        in_order(root.right);
    }
}
